home *** CD-ROM | disk | FTP | other *** search
- static char* version = "midiplay v1.0 by Günter Nagler (" __DATE__ ")";
-
- #include "midiio.hpp"
- #include <stdlib.h>
- #include <ctype.h>
- #include <string.h>
- #include <dos.h>
- #include "sb.hpp"
- #include "mpu.hpp"
- #include "sndcard.hpp"
- #include <conio.h>
- #include "timer.hpp"
-
- #define MILLISEC //timer always milliseconds
-
- class MidiPlay;
-
- Soundcard* card = 0;
- MidiPlay* midi = 0;
- int lyrics = 1;
- int gm = 0;
- long seekpos = 0;
- unsigned char vol[16];
- char playchannel[16];
-
- #define TEMPNAME "xxxxxxxx.xxx"
-
- char tempname[128] = TEMPNAME;
-
- Timer watch;
-
- class MidiPlay : public MidiRead
- {
- public:
- MidiPlay(char* name);
-
- virtual void head(unsigned version, unsigned tracks, unsigned clicksperquarter);
- virtual void track(int trackno, long length, int channel);
- virtual void endtrack(int trackno);
-
- virtual void seqnumber(unsigned int seqno);
- virtual void text(int what, int len, char* whattext, unsigned char* txt);
- virtual void meta(int what, int len, unsigned char* data);
- virtual void end();
- virtual void prefixchannel(unsigned char channel);
- virtual void prefixport(unsigned char port);
- virtual void smpteofs(int hour, int min, int sec, int frame, int fracframe);
- virtual void tact(int nom, int denom, int clicksperbeat, int notes32perbeat);
- virtual void tempo(unsigned long ticks);
- virtual void key(int signature, int isminor);
-
- virtual void program(int prg, int channel);
- virtual void control(int channel, int what, int value);
- virtual void noteon(int channel, int note, int vel);
- virtual void noteoff(int channel, int note, int vel);
- virtual void time(unsigned long ticks);
- virtual void pitchbend(int channel, int val);
- virtual void polyaftertouch(int channel, int note, int val);
- virtual void aftertouch(int channel, int val);
- virtual void songpos(unsigned pos);
- virtual void songselect(unsigned char song);
- virtual void tunerequest();
- virtual void timingclock();
- virtual void start();
- virtual void cont();
- virtual void stop();
- virtual void activesense();
- virtual void sysex(int syslen, unsigned char* sysdata);
- virtual void endmidi();
- virtual void error(const char* msg);
-
- virtual void percent(int perc);
-
- long errorcnt_;
-
- void reset();
- private:
- unsigned tactunits_;
- unsigned quarterunits_;
- unsigned long curtime_;
-
- int nl_;
- int endmark_; // each track should contain FF 2F 00 as last command
-
- unsigned long microsecperunit;
-
- unsigned char noteplaying_[16][128];
- int karaoke_;
- };
-
- static int aborted = 0;
-
- int abortkey()
- {
- if (aborted)
- return 1;
- if (kbhit() && getch() == 27)
- {
- aborted = 1;
- if (midi)
- midi->reset();
- }
- return aborted;
- }
-
- void watchdelay(int millisec)
- {
- if (millisec <= 0)
- return;
- unsigned long endtime = watch.curtime_ + millisec;
- while (watch.curtime_ < endtime)
- ;
- }
-
- void setvol(int channel, int val)
- {
- if (!card)
- return;
- unsigned char data[3];
-
- data[0] = 0xB0 + channel;
- data[1] = ctrl_volume;
- data[2] = val;
- card->play(data, 3);
- watchdelay(25);
- // printf("setvol[%d] to %d\n", channel, val);
- }
-
- MidiPlay::MidiPlay(char* name) : MidiRead(name)
- {
- nl_ = 1;
- errorcnt_ = 0;
- microsecperunit = 0;
- karaoke_ = 0;
- }
-
- void MidiPlay::head(unsigned version, unsigned tracks, unsigned clicksperquarter)
- {
- memset(noteplaying_, 0, sizeof(noteplaying_));
- quarterunits_ = clicksperquarter;
- microsecperunit = 500000L / clicksperquarter;
-
- if (tracks_ == 0)
- error("no track found");
-
- if (version != 0)
- {
- fprintf(stderr, "format %d currently not supported\n", version);
- exit(1);
- }
- }
-
- void MidiPlay::track(int trackno, long length, int channel)
- {
- endmark_ = 0;
- curtime_ = 0;
- }
-
- void MidiPlay::endtrack(int trackno)
- {
- if (!endmark_)
- printf(" // Warning: end of track meta event missing\n");
-
- if (!nl_)
- {
- nl_ = 1;
- printf("\n");
- }
- }
-
- void printchar(int c)
- {
- if (c < 0)
- return;
- if (c == '\\')
- printf("\\\\");
- else if (c == '"')
- printf("\\\"");
- else if (c != 0 && (isprint(c) || strchr("äöüÄÖÜß", c) != 0))
- putchar(c);
- else
- printf("\\x%02x", c);
- }
-
- void MidiPlay::seqnumber(unsigned int seqno)
- {
- }
-
- void MidiPlay::text(int what, int len, char* whattext, unsigned char* txt)
- {
- if (!txt)
- return;
- if (aborted)
- return;
- if (getcurtime() < seekpos)
- return;
- if (what == meta_lyric || what == meta_text)
- {
- char* bs;
-
- while ((bs = (char*)memchr(txt, '\\', len)) != 0)
- *bs = '\n';
- while ((bs = (char*)memchr(txt, '/', len)) != 0)
- *bs = '\n';
- if (*txt == '@')
- {
- karaoke_ = 1;
- txt++; len--;
- switch(*txt)
- {
- case 'K': printf("\nKind: "); break;
- case 'V': printf("\nVersion: "); break;
- case 'I': printf("\nInformation: "); break;
- case 'T': printf("\nTitle: "); break;
- case 'L': printf("\nLanguage: "); break;
- default: printf("\n@%c: ", *txt); break;
- }
- if (*txt)
- {
- txt++;
- len--;
- }
- }
- if (txt[len-1] == '\r')
- txt[len-1] = '\n';
- nl_ = txt[len-1] == '\n';
- printf("%.*s", len, txt);
- if (!karaoke_)
- printf("\n");
- }
- }
-
- void MidiPlay::meta(int what, int len, unsigned char* data)
- {
- }
-
- void MidiPlay::end()
- {
- endmark_ = 1;
- }
-
- void MidiPlay::prefixchannel(unsigned char channel)
- {
- }
-
- void MidiPlay::prefixport(unsigned char port)
- {
- }
-
-
- void MidiPlay::smpteofs(int hour, int min, int sec, int frame, int fracframe)
- {
- }
-
- void MidiPlay::tact(int nom, int denom, int clicksperbeat, int notes32perbeat)
- {
- }
-
- void MidiPlay::tempo(unsigned long microsecperbeat)
- {
- microsecperunit = microsecperbeat / quarterunits_;
- #ifndef MILLISEC
- watch.setspeed(unsigned(microsecperbeat / (quarterunits_ * 1000L)), 1);
- #endif
- }
-
- void MidiPlay::key(int signature, int isminor)
- {
- }
-
- void MidiPlay::time(unsigned long units)
- {
- if (units == 0)
- return;
- long tim = getcurtime();
- if (tim + units <= seekpos) // quick forward
- return;
- if (tim <= seekpos && seekpos > 0)
- {
- if (seekpos > 0)
- fprintf(stderr, "\rplaying...\n");
- units = tim + units - seekpos;
- for (int i = 0; i < 16; i++)
- setvol(i, vol[i]);
- }
- #ifndef MILLISEC
- int maxunits;
- do
- {
- if (abortkey())
- return;
- maxunits = 50;
- if (units < maxunits)
- maxunits = (int)units;
- watchdelay(maxunits);
- units -= maxunits;
- } while (maxunits > 0);
- #endif
-
- #ifdef MILLISEC
- unsigned millisec = (unsigned) (units * microsecperunit / 1000);
-
- do
- {
- if (abortkey())
- return;
- if (millisec >= 100)
- {
- watchdelay(100);
- millisec -= 100;
- }
- else
- {
- watchdelay(millisec);
- break;
- }
- } while (millisec > 0);
- #endif
- }
-
- void MidiPlay::program(int channel, int prg)
- {
- unsigned char s[2];
-
- if (aborted)
- return;
-
- if (!playchannel[channel])
- return;
- s[0] = 0xc0 + channel;
- s[1] = prg;
- card->play(s, 2);
- }
-
- void MidiPlay::control(int channel, int what, int value)
- {
- unsigned char s[3];
-
- if (aborted)
- return;
-
- if (!playchannel[channel])
- return;
- if (what == ctrl_volume)
- {
- if (getcurtime() < seekpos)
- {
- vol[channel] = value;
- return;
- }
- }
-
- s[0] = 0xb0 + channel;
- s[1] = what;
- s[2] = value;
- card->play(s, 3);
- }
-
- void MidiPlay::noteon(int channel, int note, int vel)
- {
- unsigned char s[3];
-
- if (aborted)
- return;
-
- if (!playchannel[channel])
- return;
- s[0] = 0x90 + channel;
- s[1] = note;
- s[2] = vel;
- card->play(s, 3);
- noteplaying_[channel][note] = 1;
- }
-
- void MidiPlay::noteoff(int channel, int note, int vel)
- {
- unsigned char s[3];
-
- if (aborted)
- return;
- if (!playchannel[channel])
- return;
- s[0] = 0x80 + channel;
- s[1] = note;
- s[2] = vel;
- card->play(s, 3);
- watchdelay(5);
- noteplaying_[channel][note] = 0;
- }
-
- void MidiPlay::pitchbend(int channel, int val)
- {
- unsigned char s[3];
-
- if (aborted)
- return;
-
- if (!playchannel[channel])
- return;
- s[0] = 0xE0 + channel;
- s[1] = val & 0x7f;
- s[2] = (val >> 7) & 0x7f;
- card->play(s, 3);
- }
-
- void MidiPlay::polyaftertouch(int channel, int note, int val)
- {
- unsigned char s[3];
-
- if (aborted)
- return;
-
- if (!playchannel[channel])
- return;
- s[0] = 0xa0 + channel;
- s[1] = note;
- s[2] = val;
- card->play(s, 3);
- }
-
- void MidiPlay::aftertouch(int channel, int val)
- {
- unsigned char s[2];
-
- if (aborted)
- return;
-
- if (!playchannel[channel])
- return;
- s[0] = 0xd0 + channel;
- s[1] = val;
- card->play(s, 2);
- }
-
- void MidiPlay::songpos(unsigned pos)
- {
- }
-
- void MidiPlay::songselect(unsigned char song)
- {
- }
-
- void MidiPlay::tunerequest()
- {
- }
-
- void MidiPlay::timingclock()
- {
- }
-
- void MidiPlay::start()
- {
- }
-
- void MidiPlay::cont()
- {
- }
-
- void MidiPlay::stop()
- {
- }
-
- void MidiPlay::activesense()
- {
- }
-
- void MidiPlay::sysex(int syslen, unsigned char* sysdata)
- {
- unsigned char c;
-
- c = 0xf0;
- card->play(&c, 1);
- card->play(sysdata, syslen);
- }
-
- void MidiPlay::endmidi()
- {
- }
-
- void MidiPlay::percent(int perc)
- {
- }
-
- void MidiPlay::error(const char* msg)
- {
- printf("// error: %s\n", msg);
- errorcnt_++;
- }
-
- void usage()
- {
- fprintf(stderr, "usage: midiplay [-gm] [-nolyric] [-seek #] [-c #] file.mid\n");
- exit(1);
- }
-
- void MidiPlay::reset()
- {
- unsigned char c[3];
-
- for (int n = 0; n < 127; n++)
- {
- for (int i = 0; i < 16; i++)
- if (noteplaying_[i][n])
- {
- c[0] = 0x80+i;
- c[1] = n;
- c[2] = 0;
- card->play(c, 3);
- noteplaying_[i][n] = 0;
- }
- }
- }
-
- int midiplayonetrack(char* filename, int temp = 0)
- {
- midi = new MidiPlay(filename);
- if (!midi)
- {
- fprintf(stderr, "not enough memory\n");
- return 1;
- }
- if (!midi->getf())
- {
- if (!temp)
- perror(filename);
- return 1;
- }
- card = detect_soundcard();
- if (!card)
- {
- fprintf(stderr, "Could not detect soundcard\n");
- return 1;
- }
-
- if (gm)
- {
- unsigned char sysex_gmreset[] = { 0xF0, 0x7E, 0x7F, 0x09, 0x01, 0xF7 };
-
- card->play(sysex_gmreset, sizeof(sysex_gmreset));
- }
-
- if (seekpos > 0)
- fprintf(stderr, "seeking...\n");
- for (int i = 0; i < 16; i++)
- {
- vol[i] = 100;
- if (seekpos > 0)
- setvol(i, 0);
- }
-
- watch.setspeed(SPEED_MILLISEC);
- unsigned long start = watch.curtime_;
- for (int t = 0; t < 1000; t++)
- if (watch.curtime_ != start)
- break;
- else if (abortkey())
- break;
- if (t >= 1000)
- {
- fprintf(stderr, "timer not working\n");
- aborted = 1;
- }
-
- midi->options_ = OPTION_NOCONTROLS | OPTION_NOSYSEVENTS;
- int ret = midi->run();
- midi->reset();
- if (aborted)
- fprintf(stderr, "aborted ...\n");
- delete card;
- if (!ret)
- {
- printf("%s: midi error at 0x%04lx\n", filename, midi->getpos());
- return 1;
- }
- return 0;
- }
-
- typedef struct
- {
- char id[4];
- char size[4]; // 6
- unsigned char fmt[2]; // 0, 1, 2
- unsigned char tracks[2];
- } MIDIHEADER;
-
- int midiplay(char* filename)
- {
- fprintf(stderr, "%s\n", filename);
- FILE* f = fopen(filename, "rb");
- if (!f)
- {
- perror(filename);
- return 1;
- }
- rewind(f);
- MIDIHEADER header;
- int ret = fread(&header, sizeof(header), 1, f);
- fclose(f);
- long size = 0;
- size = (size << 8) + header.size[0];
- size = (size << 8) + header.size[1];
- size = (size << 8) + header.size[2];
- size = (size << 8) + header.size[3];
- int format = 0;
- format = (format << 8) + header.fmt[0];
- format = (format << 8) + header.fmt[1];
- int tracks = 0;
- tracks = (tracks << 8) + header.tracks[0];
- tracks = (tracks << 8) + header.tracks[1];
- if (ret != 1 || strncmp(header.id, "MThd", 4) != 0 ||
- size != 6 || format < 0 || format > 2)
- {
- fprintf(stderr, "%s: not a standard midi file\n", filename);
- return 1;
- }
- if (format == 2)
- {
- fprintf(stderr, "%s: cannot play format 2. Use midi2to0 to convert to format 0.\n", filename);
- return 1;
- }
- if (tracks == 0)
- {
- fprintf(stderr, "%s: contains no track\n", filename);
- return 1;
- }
- if (format == 1 || tracks != 1)
- {
- char cmd[128];
-
- sprintf(cmd, "midi1to0 -q %s %s", filename, tempname);
- int ret = system(cmd);
- if (ret == 0)
- midiplayonetrack(tempname, 1);
- unlink(tempname);
- return ret;
- }
- else
- return midiplayonetrack(filename);
- }
-
- int main(int argc, char**argv)
- {
- argc--; argv++;
- for (int i = 0; i < 16; i++)
- playchannel[i] = 0;
-
- while (argc > 0 && **argv == '-')
- {
- if (strncmp(*argv, "-version", 2) == 0)
- {
- fprintf(stderr, "%s\n", version);
- argc--; argv++;
- if (argc == 0)
- return 0;
- continue;
- }
- if (argc > 0 && strncmp(*argv, "-nolyric", 2) == 0)
- {
- lyrics = 0;
- argc--; argv++;
- continue;
- }
- if (argc > 0 && strncmp(*argv, "-seek", 2) == 0)
- {
- argc--; argv++;
- if (argc == 0)
- fprintf(stderr, "option -seek needs a position\n");
- else
- {
- char* end;
-
- seekpos = strtoul(*argv, &end, 0);
- argc--; argv++;
- }
- continue;
- }
- if (argc > 0 && strncmp(*argv, "-c", 2) == 0)
- {
- argc--; argv++;
- if (argc == 0)
- fprintf(stderr, "option -c needs a channel number (1-16)\n");
- else
- {
- char* end;
- long ch;
-
- ch = strtoul(*argv, &end, 0);
- if (ch <= 0 || ch > 16)
- fprintf(stderr, "invalid channel number %s (should be 1-16)\n", *argv);
- else
- playchannel[(int)ch-1] = 1;
- argc--; argv++;
- }
- continue;
- }
- if (argc > 0 && strncmp(*argv, "-gm", 2) == 0)
- {
- gm = 1;
- argc--; argv++;
- continue;
- }
- fprintf(stderr, "invalid option %s\n", *argv);
- argc--; argv++;
- usage();
- }
- if (argc == 0)
- usage();
-
- for (i = 0; i< 16; i++)
- if (playchannel[i])
- break;
- if (i >= 16)
- for (i = 0; i< 16; i++) // default: play all channels
- playchannel[i] = 1;
-
- return midiplay(*argv);
- }
-
-